import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment
import android.util.Log
import android.util.LruCache
import com.blankj.utilcode.util.ThreadUtils.runOnUiThread
import com.jakewharton.disklrucache.DiskLruCache
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.*
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

class BitmapUtils private constructor(context: Context) {
    companion object {
        @Volatile
        private var instance: BitmapUtils? = null

        fun getInstance(context: Context): BitmapUtils =
            instance ?: synchronized(this) {
                instance ?: BitmapUtils(context.applicationContext).also { instance = it }
            }
    }

    // 内存缓存（L1）
    private val memoryCache: LruCache<String, Bitmap>

    // 本地缓存（L2）
    private val diskCache: DiskLruCache
    private val diskCacheDir: File
    private val DISK_CACHE_SIZE = 10 * 1024 * 1024L // 10MB
    private val DISK_CACHE_SUBDIR = "bitmap_cache"

    init {
        // 初始化内存缓存
        val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
        val cacheSize = maxMemory / 8 // 使用1/8的可用内存作为缓存
        memoryCache = object : LruCache<String, Bitmap>(cacheSize) {
            override fun sizeOf(key: String, bitmap: Bitmap): Int {
                return bitmap.byteCount / 1024 // 以KB为单位
            }
        }

        // 初始化本地缓存
        diskCacheDir = getDiskCacheDir(context, DISK_CACHE_SUBDIR)
        if (!diskCacheDir.exists()) {
            diskCacheDir.mkdirs()
        }
        diskCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE)
    }

    // 获取缓存目录
    private fun getDiskCacheDir(context: Context, uniqueName: String): File {
        val cachePath = if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() ||
            !isExternalStorageRemovable()
        ) {
            context.externalCacheDir?.path ?: context.cacheDir.path
        } else {
            context.cacheDir.path
        }
        return File(cachePath + File.separator + uniqueName)
    }

    // 判断外部存储是否可移除
    private fun isExternalStorageRemovable(): Boolean {
        return Environment.isExternalStorageRemovable()
    }

    // 从缓存或网络加载图片
    fun loadBitmap(url: String, reqWidth: Int, reqHeight: Int, callback: (Bitmap?) -> Unit) {
        val key = hashKeyForDisk(url)

        // 1. 检查内存缓存
        val memoryBitmap = getBitmapFromMemoryCache(key)
        if (memoryBitmap != null) {
            runOnUiThread {
                callback(memoryBitmap)
            }
            return
        }

        // 2. 检查本地缓存（异步）
        Thread {
            val diskBitmap = getBitmapFromDiskCache(key, reqWidth, reqHeight)
            if (diskBitmap != null) {
                // 放入内存缓存
                addBitmapToMemoryCache(key, diskBitmap)
                // 返回结果
                runOnUiThread {
                    callback(diskBitmap)
                }
                return@Thread
            }

            // 3. 从网络加载（异步）
            try {
                val client = OkHttpClient()
                val request = Request.Builder()
                    .url(url)
                    .build()

                client.newCall(request).enqueue(object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        // 加载失败处理
                        Log.i("OkHttp", "请求失败: ${e.message}")
                        runOnUiThread {
                            callback(null)
                        }
                    }

                    override fun onResponse(call: Call, response: Response) {
                        if (!response.isSuccessful) {
                            Log.e("BitmapUtils", "响应失败: ${response.code}")
                            runOnUiThread {
                                callback(null)
                            }
                            return
                        }

                        val bitmap = decodeSampledBitmapFromStream(response.body?.byteStream(),reqWidth,reqHeight)

                        // 保存到本地缓存
                        saveBitmapToDiskCache(key, bitmap!!)
                        // 放入内存缓存
                        addBitmapToMemoryCache(key, bitmap!!)
                        // 返回结果
                        runOnUiThread {
                            callback(bitmap)
                        }
                    }
                })
            } catch (e: Exception) {
                e.printStackTrace()
                runOnUiThread {
                    callback(null)
                }
            }
        }.start()
    }

    // 添加Bitmap到内存缓存
    private fun addBitmapToMemoryCache(key: String, bitmap: Bitmap) {
        if (getBitmapFromMemoryCache(key) == null) {
            memoryCache.put(key, bitmap)
        }
    }

    // 从内存缓存获取Bitmap
    private fun getBitmapFromMemoryCache(key: String): Bitmap? {
        return memoryCache.get(key)
    }

    // 从本地缓存获取Bitmap（兼容版本）
    private fun getBitmapFromDiskCache(key: String, reqWidth: Int, reqHeight: Int): Bitmap? {
        val snapshot = diskCache.get(key) ?: return null
        try {
            // 使用反射获取输入流
            val inputStream = getInputStream(snapshot) ?: return null
            return decodeSampledBitmapFromStream(inputStream, reqWidth, reqHeight)
        } catch (e: IOException) {
            e.printStackTrace()
            return null
        }
    }

    // 保存Bitmap到本地缓存（兼容版本）
    private fun saveBitmapToDiskCache(key: String, bitmap: Bitmap) {
        var editor: DiskLruCache.Editor? = null
        try {
            editor = diskCache.edit(key)
            if (editor != null) {
                // 使用反射获取输出流
                val outputStream = getOutputStream(editor) ?: return
                bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream)
                outputStream.flush()
                outputStream.close()
                editor.commit()
            }
        } catch (e: Exception) {
            e.printStackTrace()
            editor?.abort()
        }
    }

    // 使用反射获取输入流（兼容不同版本）
    private fun getInputStream(snapshot: DiskLruCache.Snapshot): InputStream? {
        return try {
            // 尝试调用 getInputStream(0) 方法
            val method = snapshot.javaClass.getMethod("getInputStream", Int::class.java)
            method.invoke(snapshot, 0) as InputStream
        } catch (e: Exception) {
            try {
                // 尝试通过反射获取文件再打开流
                val fileField = snapshot.javaClass.getDeclaredField("file")
                fileField.isAccessible = true
                val file = fileField.get(snapshot) as File
                FileInputStream(file)
            } catch (e2: Exception) {
                null
            }
        }
    }

    // 使用反射获取输出流（兼容不同版本）
    private fun getOutputStream(editor: DiskLruCache.Editor): OutputStream? {
        return try {
            // 尝试调用 newOutputStream(0) 方法
            val method = editor.javaClass.getMethod("newOutputStream", Int::class.java)
            method.invoke(editor, 0) as OutputStream
        } catch (e: Exception) {
            null
        }
    }

    // 从输入流解码并二次采样Bitmap
    private fun decodeSampledBitmapFromStream(
        inputStream: InputStream?,
        reqWidth: Int,
        reqHeight: Int
    ): Bitmap? {
        // 将输入流内容写入 ByteArrayOutputStream
        val byteArrayOutputStream = ByteArrayOutputStream()
        val buffer = ByteArray(4096)
        var bytesRead: Int

        while (inputStream?.read(buffer).also { bytesRead = it!! } != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead)
        }

        // 转换为 ByteArray 用于解码
        val byteArray = byteArrayOutputStream.toByteArray()
        // 第一次采样：获取尺寸
        val options = BitmapFactory.Options().apply {
            inJustDecodeBounds = true

            // 第一次解析获取尺寸
            BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, this)

            // 计算采样率（根据目标尺寸优化内存）
            inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)
            inJustDecodeBounds = false

            // 设置像素格式以减少内存占用
            inPreferredConfig = Bitmap.Config.RGB_565
        }

        // 第二次采样：加载实际图片
        return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)
    }

    // 计算采样率
    private fun calculateInSampleSize(
        options: BitmapFactory.Options,
        reqWidth: Int,
        reqHeight: Int
    ): Int {
        val (height: Int, width: Int) = options.run { outHeight to outWidth }
        var inSampleSize = 1

        if (height > reqHeight || width > reqWidth) {
            val halfHeight: Int = height / 2
            val halfWidth: Int = width / 2

            // 计算最大的 inSampleSize 值，该值为2的幂，且使图片尺寸大于等于要求的尺寸
            while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
                inSampleSize *= 2
            }
        }

        return inSampleSize
    }

    // 生成缓存键（使用MD5哈希）
    private fun hashKeyForDisk(key: String): String {
        return try {
            val messageDigest = MessageDigest.getInstance("MD5")
            messageDigest.update(key.toByteArray())
            bytesToHexString(messageDigest.digest())
        } catch (e: NoSuchAlgorithmException) {
            key.hashCode().toString()
        }
    }

    private fun bytesToHexString(bytes: ByteArray): String {
        val sb = StringBuilder()
        for (byte in bytes) {
            val hex = Integer.toHexString(0xFF and byte.toInt())
            if (hex.length == 1) {
                sb.append('0')
            }
            sb.append(hex)
        }
        return sb.toString()
    }

    // 关闭并清理缓存
    fun clearCache() {
        try {
            diskCache.delete()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        memoryCache.evictAll()
    }
}